(library (fileio)
  (export get-string-from-file
          get-lines-from-file
          get-lines-from-port
          get-lines-from-file-using-splitting
          put-lines-to-file
          put-string-to-file)
  (import
   (except (rnrs base)
           let-values
           map)
   (only (guile)
         lambda* λ
         ;; ports and files
         call-with-input-file
         call-with-output-file
         set-port-encoding!
         eof-object?
         ;; string
         string-split
         string-join)
   (ice-9 textual-ports)  ; for textual reading and writing procedures
   (ice-9 binary-ports)  ; not sure if needed
   (ice-9 rdelim)  ; for `eof-object?`
   (ice-9 optargs)  ; for keyword arguments
   ;; not sure if needed
   (srfi srfi-1))


  (define get-string-from-file
    (lambda* (file-path
              #:key
              (encoding "UTF-8"))
      (call-with-input-file file-path
        (λ (port)
          (set-port-encoding! port encoding)
          (get-string-all port)))))


  (define get-lines-from-file
    (lambda* (file-path
              #:key
              (encoding "UTF-8"))
      ;; another common encoding is: "ISO-8859-1"
      ;; see http://www.iana.org/assignments/character-sets for more
      (define (get-lines-from-port port)
        (let ([line (get-line port)])
          (cond [(eof-object? line) '()]
                [else
                 (cons line
                       (get-lines-from-port port))])))
      (call-with-input-file file-path
        (λ (port)
          (set-port-encoding! port encoding)
          (get-lines-from-port port)))))


  (define get-lines-from-file-using-splitting
    (lambda* (file-path
              #:key
              (encoding "UTF-8"))
      (string-split (get-string-from-file file-path #:encoding encoding)
                    ;; You could use simple character here, but I am using
                    ;; lambda to show that it can be used as well.
                    (λ (char) (char=? char #\newline)))))


  (define put-lines-to-file
    (lambda* (file-path
              lines
              #:key
              (encoding "UTF-8")
              (mode 'replace))
      (call-with-output-file file-path
        (λ (port)
          (set-port-encoding! port encoding)
          (put-string port
                      (cond
                       [(eq? mode 'append)
                        (string-append (get-string-from-file
                                        file-path
                                        #:encoding encoding)
                                       "\n"
                                       (string-join lines "\n"))]
                       [(equal? mode 'replace) (string-join lines "\n")]
                       [else (string-join lines "\n")]))))))


  (define put-string-to-file
    (lambda* (file-path
              string
              #:key
              (encoding "UTF-8")
              (mode 'replace))
      (call-with-output-file file-path
        (λ (port)
          (set-port-encoding! port encoding)
          (put-string port
                      (cond
                       [(eq? mode 'append)
                        (string-append (get-string-from-file
                                        file-path
                                        #:encoding encoding)
                                       "\n"
                                       string)]
                       [(equal? mode 'replace) string]
                       [else string])))))))
